package zulu.test;

import java.nio.FloatBuffer;

import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL3;
import com.jogamp.opengl.GLException;

import owg.util.Calc;
import owg.util.euclidian.MatrixStack;
import owg.util.opengl.BlendMode;
import owg.util.opengl.ColorF;
import owg.util.opengl.EGL3;
import owg.util.opengl.ShaderLib;
import owg.util.opengl.ShaderProgram;
import owg.util.opengl.TextureLib;
import world.Global;
import bogus.core.BogusCore;
import bogus.core.CoreParams;
import bogus.minigame.MinigameBase;

public class XBR implements MinigameBase
{
    static final int W = 160, H = 120;
    int renderTexture;
    int depthTexture;
    int fbo;
    int vbo;
    ShaderProgram shader;
    @Override
    public void init() {
	try {
	    shader = ShaderLib.get(BogusCore.egl, Global.streamRelative("res/shaders/xBR.vert"), Global.streamRelative("res/shaders/xBR.frag"));
	} catch (Exception e) {
	    throw new RuntimeException(e);
	}
	EGL3 egl = BogusCore.egl;
	GL3 gl = egl.getGL();
	
	int[] buf = new int[2];
	gl.glGenTextures(2, buf, 0);
	renderTexture = buf[0];
	depthTexture = buf[1];
	
	gl.glBindTexture(GL3.GL_TEXTURE_2D, depthTexture);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_S, GL3.GL_REPEAT);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_T, GL3.GL_REPEAT);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_NEAREST);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_NEAREST);
	gl.glTexImage2D(GL3.GL_TEXTURE_2D, 0, GL3.GL_DEPTH_STENCIL, W, H, 0, GL3.GL_DEPTH_STENCIL, GL3.GL_UNSIGNED_INT_24_8, null);
	
	gl.glBindTexture(GL3.GL_TEXTURE_2D, renderTexture);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_S, GL3.GL_REPEAT);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_T, GL3.GL_REPEAT);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_NEAREST);
	gl.glTexParameteri(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_NEAREST);
	gl.glTexImage2D(GL3.GL_TEXTURE_2D, 0, GL3.GL_RGB, W, H, 0, GL3.GL_RGB, GL3.GL_UNSIGNED_BYTE, null);
	
	gl.glBindTexture(GL3.GL_TEXTURE_2D, 0);
	
	gl.glGenFramebuffers(1, buf, 0);
	fbo = buf[0];
	
	gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, fbo);
	
	gl.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_COLOR_ATTACHMENT0, GL3.GL_TEXTURE_2D, renderTexture, 0);
	gl.glFramebufferTexture2D(GL3.GL_FRAMEBUFFER, GL3.GL_DEPTH_STENCIL_ATTACHMENT, GL3.GL_TEXTURE_2D, depthTexture, 0);
	
	int status = gl.glCheckFramebufferStatus(GL3.GL_FRAMEBUFFER);
	if(status != GL3.GL_FRAMEBUFFER_COMPLETE)
		throw new GLException("Framebuffer status error code: "+status);
	
	gl.glGenBuffers(1, buf, 0);
	vbo = buf[0];
	FloatBuffer data = FloatBuffer.allocate(4*2*2);
	//v0 t0
	data.put(-1); data.put(-1);
	data.put(0); data.put(0);//data.put(0); data.put(0);
	//v1 t1
	data.put(1f); data.put(-1);
	data.put(1); data.put(0);//data.put(1); data.put(0);
	//v2 t2
	data.put(-1); data.put(1);
	data.put(0); data.put(1);//data.put(0); data.put(1);
	//v3 t3
	data.put(1); data.put(1);
	data.put(1); data.put(1);//data.put(1); data.put(1);
	data.rewind();
	gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo);
	gl.glBufferData(GL3.GL_ARRAY_BUFFER, data.capacity()*Calc.bytesPerFloat, data, GL3.GL_STATIC_DRAW);
	gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
    }

    @Override
    public CoreParams getCoreParams() {
	return new CoreParams();
    }

    @Override
    public void step() {
    }

    @Override
    public void render() {
	EGL3 egl = BogusCore.egl;
	GL3 gl = egl.getGL();
	egl.setCullFaceEnabled(false);
	MatrixStack mp = egl.projectionMatrix();
	MatrixStack mv = egl.modelviewMatrix();
	
	gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, fbo);
	egl.setViewport(0, 0, W, H);
	mp.identity();
	mv.identity();
	
	mp.ortho(0, W, H, 0, -1, 1);
	egl.clearScreen(ColorF.RED);
	egl.setBlendMode(BlendMode.NORMAL);
	egl.useProgram(egl.defaultShaderProgram);
	egl.enableTexture2D(TextureLib.tex("banaan"), 0);
	mv.push();
	mv.translatef(0, 8, 0);
	mv.scalef(32, 32, 1);
	egl.nwSquare.render();
	mv.pop();
	mv.push();
	mv.translatef(60, 40, 0);
	mv.scalef(32, 32, 1);
	egl.nwSquare.render();
	mv.pop();
	mv.push();
	egl.enableTexture2D(TextureLib.tex("tails"), 0);
	mv.translatef(16, 60, 0);
	mv.scalef(36, 31, 1);
	egl.nwSquare.render();
	mv.pop();
	egl.disableTexture2D();

	gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0);
	egl.setViewport(0, 0, BogusCore.panel.getWidth(), BogusCore.panel.getHeight());
	mp.identity();
	mv.identity();
	egl.useProgram(shader);
	
	gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo);
	//Uniforms
	int rubyTextureSizeLoc = gl.glGetUniformLocation(shader.program, "rubyTextureSize");
	gl.glUniform2f(rubyTextureSizeLoc, W, H);
	int samplerLoc = gl.glGetUniformLocation(shader.program, "rubyTexture");
	gl.glUniform1i(samplerLoc, 0);
	//Attribs
	int vertexLoc = gl.glGetAttribLocation( shader.program, "vertex_position" );
	gl.glEnableVertexAttribArray( vertexLoc );
	gl.glVertexAttribPointer( vertexLoc, 4, GL.GL_FLOAT, false, 4*Calc.bytesPerFloat, 0 );
	int texcoordLoc = gl.glGetAttribLocation( shader.program, "vertex_texcoord" );
	gl.glEnableVertexAttribArray( texcoordLoc );
	gl.glVertexAttribPointer( texcoordLoc, 2, GL.GL_FLOAT, false, 4*Calc.bytesPerFloat, 2*Calc.bytesPerFloat );
	
	egl.enableTexture2D(renderTexture, W, H);
	egl.setBlendMode(BlendMode.REPLACE);
	
	gl.glDrawArrays(GL3.GL_TRIANGLE_STRIP, 0, 4);
	
	gl.glDisableVertexAttribArray(vertexLoc);
	gl.glDisableVertexAttribArray(texcoordLoc);
	gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
    }

    @Override
    public void dispose() {
	EGL3 egl = BogusCore.egl;
	GL3 gl = egl.getGL();
	gl.glDeleteFramebuffers(1, new int[]{fbo}, 0);
	gl.glDeleteTextures(2, new int[]{renderTexture, depthTexture}, 0);
	gl.glDeleteBuffers(1, new int[]{vbo}, 0);
    }

}
